#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "gr.h"
#include "checkGr.h"

static int checkIzq (char ** prod, char * st);
static int checkDerEn (char ** prod, char * st, char * snt);
static int presentS (char * prod, char * symbols);
static int contains (char * symbols, char c);
static void freeAll (char ** prod, char * st, char * snt);

int validGr (grADT gr) {
	char * snt = getGrSNT(gr);
	char * st = getGrST(gr);
	char ** prod = getGrProd(gr);
	int ret;
	
	ret = (checkIzq(prod, snt) && checkDerEn(prod, st, snt));
	return ret;
}

int regDer (grADT gr) {
	char * snt = getGrSNT(gr);
	char * st = getGrST(gr);
	char ** prod = getGrProd(gr);
	char * production;
	int i, j, chars = 0, syt = 0, nt = 0, lambda = 0;

	for (i = 0; prod[i] != NULL; i++) {
		production = calloc(1, strlen(prod[i])+1);
		strcpy(production, prod[i]);
		while (*production != '-' && *production != '\0') {
			chars++;
			if (chars > 1) {
				return 0;
			}
			production++;
		}
		production += 2; /* Salteo la flecha */
		chars = syt = nt = 0;
		for (j = 0; production[j] != '\0'; j++) {
			if (production[j] == '\\') {
				lambda = 1;
			} else {
				if (production[j] == '|') {
					if (!(chars <= 2 && (syt == 1 || lambda) && nt <= 1)) {
						return 0;
					}
				      chars = syt = nt = lambda = 0;
				} else {
					if (contains(st, production[j])) {
						syt = 1;
						chars++;
					} else if (contains(snt, production[j])) {
						if (syt == 0) {
							return 0;
						}
						nt++;
						chars++;
					}
				 }
			}
		}
		if (!(chars <= 2 && (syt == 1 || lambda) && nt <= 1)) {
			return 0;
		}
		chars = syt = nt = lambda = 0;
	}

	return 1;
}

int regIzq (grADT gr) {
	char * snt = getGrSNT(gr);
	char * st = getGrST(gr);
	char ** prod = getGrProd(gr);
	char * production;
	int i, j, chars = 0, syt = 0, nt = 0, lambda = 0;

	for (i = 0; prod[i] != NULL; i++) {
		production = calloc(1, strlen(prod[i])+1);
		strcpy(production, prod[i]);
		while (*production != '-' && *production != '\0') {
			chars++;
			if (chars > 1) {
				return 0;
			}
			production++;
		}
		production += 2; /* Salteo la flecha */
		if (strcmp(production, "\\") == 0) {
			continue;
		}
		chars = syt = nt = 0;
		for (j = 0; production[j] != '\0'; j++) {
			if (production[j] == '\\') {
				lambda = 1;
			} else {
				if (production[j] == '|') {
					if (!(chars <= 2 && (syt == 1 || lambda) && nt <= 1)) {
						return 0;
					}
					chars = syt = nt = lambda = 0;
				} else {
					if (contains(snt, production[j])) {
						if (syt == 1) {
							return 0;
						}
						nt = 1;
						chars++;
					} else if (contains(st, production[j])) {
						syt = 1;
						chars++;
					}
				}
			}
		}
		if (!(chars <= 2 && (syt == 1 || lambda) && nt <= 1)) {
			return 0;
		}
		chars = syt = nt = lambda = 0;
	}

	return 1;
}

static int checkDerEn (char ** prod, char * st, char * snt) {
	int i;
	char * symbols = calloc(1, strlen(st)+strlen(snt)+1+1);
	char * production;

	for (i = 0; prod[i] != NULL; i++) {
		production = calloc(1, strlen(prod[i])+1);
		strcpy(production, prod[i]);
		while (*production != '>') {
			production++;
		}
		production++;
		strcat(symbols, st);
		strcat(symbols, snt);
		strcat(symbols, "\\");
		if (!presentS(production, symbols)) {
			return 0;
		}
	}
	return 1;
}

static int checkIzq (char ** prod, char * snt) {
	int i;

	for (i = 0; prod[i] != NULL; i++) {
		if (!presentS(prod[i], snt)) {
			return 0;
		}
	}

	return 1;
}

static int presentS (char * prod, char * symbols) {
	int i;
	
	for (i = 0; prod[i] != '-' && prod[i] != '\0'; i++) {
		if (prod[i] != '|' && !contains(symbols, prod[i])) {
			return 0;
		}
	}

	return 1;
}

static int contains (char * symbols, char c) {
	int i, len = strlen(symbols);

	for (i = 0; i < len; i++) {
		if (c == symbols[i]) {
			return 1;
		}
	}

	return 0;
}

static void freeAll (char ** prod, char * st, char * snt) {
	int i;
	if (st != NULL) {
		free(st);
	}
	if (snt != NULL) {
		free(snt);
	}
	for (i = 0; prod[i] != NULL; i++) {
		free(prod[i]);
	}
	free (prod);
}

